<?php

class Default_Model_Users extends Zend_Db_Table_Abstract {
	protected $_name = 'users';
	protected $_primary = array('id');
	protected $_cols = array(
		'id',
		'name',
		'email',
		'password',
		'role',
		'register_ip',
		'register_date',
		'login_ip',
		'login_date',
		'hash'
	);
	
	/**
	 * Zwraca adapter potwierdzenia autetyczności
	 *
	 * @return Zend_Auth_Adapter_DbTable
	 */
	public function getAuthAdapter() {
		// Ustaw adapter autoryzacji
		$userModel = new Default_Model_Users();
		return $authAdapter = new Zend_Auth_Adapter_DbTable(
			Zend_Db_Table_Abstract::getDefaultAdapter(),
			$userModel->info(Default_Model_Users::NAME),
			'email',
			'password');
	}

	/**
	 * Loguje użytkownika
	 *
	 * @param  $mail Adres mail
	 * @param  $password hasło
	 * @return Zend_Auth_Result
	 */
	public function login($mail, $password) {
		if (empty($mail) || empty($password)) {
			return null;
		}
		
		// Pobierz referencje do singletonu instancji Zend_Auth
		$auth = Zend_Auth::getInstance();
		
		// adapter potwierdzenia autetyczności + wpisanie loginu i hasła
		$authAdapter = $this->getAuthAdapter();
		$authAdapter
			->setIdentity($mail)
			->setCredential(hash('whirlpool', $password));
		
		// Próba potwierdzenia autetyczności, zapisanie wyniku
		$result = $auth->authenticate($authAdapter);
		
		// Autentyfikacja zakończona sukcesem; dane zapisane w sesji
		if ($result->isValid()) {
			// dodaj troche wiecej szczegolow
			$auth->getStorage()->write($authAdapter->getResultRowObject(array('id', 'name', 'email', 'role')));
			
			// ostatni IP
			$this->updateUser($auth->getIdentity()->id, array(
				'login_date' => time(),
				'login_ip' => intval(sprintf('%u', ip2long($_SERVER['REMOTE_ADDR'])))
			));
		}
		
		return $result;
	}
	
	/**
	 * Rejestruje nowego użytkownika w systemie
	 *
	 * @param string $name Nick usera
	 * @param string $email Email użytkownika
	 * @param string $password Hasło do konta
	 * 
	 * @return int|false ID nowostworzonego konta, lub false w przypadku bledu
	 */
	public function register($name, $email, $password) {
		if (!Zend_Validate::is($name, 'Alnum') || !Zend_Validate::is($email, 'EmailAddress') || strlen($password) < 5)
			return false;
		try {
			return $this->insert(array(
				'name' => $name,
				'email' => $email,
				'password' => hash('whirlpool', $password),
				'register_date' => time(),
				'role' => 'user',
				'register_ip' => intval(sprintf('%u', ip2long($_SERVER['REMOTE_ADDR'])))
			));
		} catch (Zend_Db_Statement_Exception $e) {
			Zend_Registry::get('Zend_Log')->crit('Creating user "' . $name . '#' . $email .'" error: ' . $e->getMessage());
			return false;
		}
	}
	
	/**
	 * Sprawdza, czy użytkownik o podanym nicku istnieje w bazie
	 *
	 * @param string $name Nazwa użytkownika
	 * @return bool
	 */
	public function nickExists($name) {
		if (!Zend_Validate::is($name, 'Alnum'))
			return false;
		return $this->select()
			->from($this->_name, array('id'))
			->where('name = ?', $name)
			->limit(1)
			->query()->fetch() !== false;
	}
	
	/**
	 * Sprawdza, czy użytkownik o podanym emailu istnieje w bazie
	 *
	 * @param string $email Nazwa użytkownika
	 * @return bool
	 */
	public function mailExists($email) {
		if (!Zend_Validate::is($email, 'EmailAddress'))
			return false;
		return $this->select()
			->from($this->_name, array('id'))
			->where('email = ?', $email)
			->limit(1)
			->query()->fetch() !== false;
	}
	
	/**
	 * Pobiera dane o użytkowniku na podstawie jego ID
	 *
	 * @param int $id ID użytkownika w sysytemie
	 * @return StdClass
	 */
	public function getUserById($id) {
		if (!is_numeric($id))
			return false;
		
		return $this->select()
			->from($this->_name, $this->_cols)
			->where('id = ?', intval($id))
			->limit(1)
			->query()->fetch();
	}
	
	/**
	 * Pobiera dane o użytkowniku o podanym mailu
	 *
	 * @param string $mail Adres email poszukiwanego użyszkodnika
	 * @return StdClass
	 */
	public function getUserByMail($mail) {
		if (!Zend_Validate::is($mail, 'EmailAddress'))
			return false;
		
		return $this->select()
			->from($this->_name, $this->_cols)
			->where('email = ?', $mail)
			->limit(1)
			->query()->fetch();
	}
	
	/**
	 * Uaktualnia hash podanemu użytkownikowi
	 *
	 * @param string|int $id Adres email lub ID użytkownika
	 * @return string | false Nowy hash w przypadku powodzenia lub false, kiedy użytkownik nie istnieje
	 */
	public function hashUpdate($id) {
		if (Zend_Validate::is($id, 'EmailAddress')) {
			$user = $this->getUserByMail($id);
		} else if (is_numeric($id)) {
			$user = $this->getUserById($id);
		}
		
		if (!($user instanceof StdClass))
			return false;
		
		$time = time();
		$rand = rand(46656, 60466175); //zeby nie losowal malych liczb i zeby po przekonwertowaniu do podstawy 36, liczba miescila sie w zakresie 01000_36 i zzzzz_36
		$hash = md5($user->id . $rand . $time);
		if ($this->update(
			array('hash' => $hash),
			array($this->getAdapter()->quoteInto('id = ?', $user->id))
		))
		return str_pad(base_convert($rand, 10, 36), 5, 0, STR_PAD_LEFT) .
			base_convert($user->id, 10, 36) .
			str_pad(base_convert($time, 10, 36), 7, 0, STR_PAD_LEFT);
		return false;
	}
	
	/**
	 * Uaktualnia informacje o użytkowniku o podanym ID
	 *
	 * @param int $id ID użytkownika
	 * @param array $data Dane do uaktualnienia
	 * @return bool Czy uaktualniono, czy nie
	 */
	public function updateUser($id, $data) {
		if (!is_numeric($id) || !is_array($data) || empty($data))
			return false;
		// zahaszuj hasło
		if (isset($data['password']) && !empty($data['password']))
			$data['password'] = hash('whirlpool', $data['password']);
		else
			unset($data['password']);
		
		foreach ($data as &$field) {
			if (is_null($field))
				$field = new Zend_Db_Expr('null');
		}
		
		return $this->update(
			array_filter(array_intersect_key($data, array_fill_keys($this->_cols, null))),
			array($this->getAdapter()->quoteInto('id = ?', intval($id)))) > 0;
	}
}